import { Injectable } from '@angular/core';
// 导入数据
import { Hero } from './hero';
import { HEROES } from './mock-heroes';
// 从 RxJS 中导入 Observable 和 of 符号。
import { Observable, of } from 'rxjs';
// 引入 message service
import { MessageService } from './message.service';
// 引入 HttpClient 发送请求的
import { HttpClient, HttpHeaders } from '@angular/common/http';

// 引入捕获错误的模块
import { catchError, map, tap } from 'rxjs/operators';


@Injectable({ //用根注入器将你的服务注册成为提供商,自动有的
  providedIn: 'root'
})
export class HeroService {

  private heroesUrl = 'api/heroes';  // URL to web api   

  // 声明 message 服务，这相当于在服务里面再次引入服务了，
  // 感觉像是总的方法里面，引入各种专门的方法
  constructor(
    private messageService: MessageService,
    private http: HttpClient) { }

  // 得到英雄的方法，类名Hero[],方法返回 HEROS
  // 这里类名那加了个 Observable,返回时 加了of()
  // getHeroes(): Observable<Hero[]> {
  //   // 调用这个 messageService 里面的 add 方法，向 messages 数组里 push
  //   this.messageService.add('HeroService: fetched heroes');
  //   return of(HEROES);
  // }

  // 把该方法转换成使用 HttpClient 的
  getHeroes (): Observable<Hero[]> {
    return this.http.get<Hero[]>(this.heroesUrl)
      .pipe(tap(_ => this.log('fetched heroes')), // 使用  tap 来记录各种操作。
        catchError(this.handleError<Hero[]>('getHeroes', [])) // 捕获异常
      );
  }

  // 看不懂，写上就对了
  private handleError<T> (operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
   
      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead
   
      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);
   
      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }

  // getHero(id: number): Observable<Hero> {
  //   // TODO: send the message _after_ fetching the hero
  //   this.messageService.add(`HeroService: fetched hero id=${id}`);
  //   // 在 HEROES 里面查找
  //   return of(HEROES.find(hero => hero.id === id));
  // }

  /** GET hero by id. Will 404 if id not found */
  getHero(id: number): Observable<Hero> {
    const url = `${this.heroesUrl}/${id}`;
    return this.http.get<Hero>(url).pipe(
      tap(_ => this.log(`fetched hero id=${id}`)),
      catchError(this.handleError<Hero>(`getHero id=${id}`))
    );
  }


  private log(message: string) {
    this.messageService.add(`HeroService: ${message}`);
  }

  // 会使用 http.put() 来把修改后的英雄保存到服务器上。
  /** PUT: update the hero on the server */
  updateHero (hero: Hero): Observable<any> {

    const httpOptions = {
      headers: new HttpHeaders({ 'Content-Type': 'application/json' })
    };

    return this.http.put(this.heroesUrl, hero, httpOptions).pipe(
      tap(_ => this.log(`updated hero id=${hero.id}`)),
      catchError(this.handleError<any>('updateHero'))
    );
  }


  /** POST: add a new hero to the server */
  addHero (hero: Hero): Observable<Hero> {
    const httpOptions = {
      headers: new HttpHeaders({ 'Content-Type': 'application/json' })
    };
    return this.http.post<Hero>(this.heroesUrl, hero, httpOptions)
    .pipe(
      tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)), // 记录数据
      catchError(this.handleError<Hero>('addHero')) // 捕获异常
    );
  }

  /** DELETE: delete the hero from the server */
  deleteHero (hero: Hero | number): Observable<Hero> {
    // 如果 hero 的类型 是number,返回 hero
    // 如果 hero 的类型 不是number,返回 hero.id
    const id = typeof hero === 'number' ? hero : hero.id;
    // url="this.heroesUrl/id"
    const url = `${this.heroesUrl}/${id}`;
    const httpOptions = {
      headers: new HttpHeaders({ 'Content-Type': 'application/json' })
    };
    return this.http.delete<Hero>(url, httpOptions).pipe(
      tap(_ => this.log(`deleted hero id=${id}`)),
      catchError(this.handleError<Hero>('deleteHero'))
    );
  }


  // 搜索
  /* GET heroes whose name contains search term */
  searchHeroes(term: string): Observable<Hero[]> {
    if (!term.trim()) { //trim 去掉两边的空
      // 如果没有搜索词，该方法立即返回一个空数组
      // if not search term, return empty hero array.
      return of([]);
    }
    return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`)
    .pipe(
      tap(_ => this.log(`found heroes matching "${term}"`)),
      catchError(this.handleError<Hero[]>('searchHeroes', []))
    );
}

}
